/**
 * 
 */
package pl.lodz.p.browarex.ws;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.http.HttpsUrlConnectionMessageSender;

/**
 * @author Rafi
 * 
 */
public abstract class AbstractSSLEndpoint {

	private static final Log log = LogFactory.getLog(AbstractSSLEndpoint.class);
	
	@Value("${keystore.algorithm}")
	protected String keyManagerAlgorithm;
	
	@Value("${truststore.algorithm}")
	protected String trustAlgorithm;

	@Autowired
	private WebServiceTemplate ws;
	
	public AbstractSSLEndpoint() {
		super();
	}

	private boolean performed = false;

	public abstract File getKeyStoreFile();

	public abstract String getKeyStorePass();

	public abstract File getTrustStoreFile();

	public abstract String getTrustStorePass();

	protected HttpsUrlConnectionMessageSender setHttpsMessageSender()
			throws KeyStoreException, NoSuchAlgorithmException,
			CertificateException, FileNotFoundException, IOException,
			UnrecoverableKeyException {

		HttpsUrlConnectionMessageSender msgSender = new HttpsUrlConnectionMessageSender();

		KeyManagerFactory keyManagerFactory = this.getKeyManagerFactory(
				getKeyStoreFile(), getKeyStorePass());

		TrustManagerFactory trustManagerFactory = this.getTrustManagerFactory(
				getTrustStoreFile(), getTrustStorePass());

		msgSender.setKeyManagers(keyManagerFactory.getKeyManagers());
		msgSender.setTrustManagers(trustManagerFactory.getTrustManagers());

		msgSender.setSecureRandom(new SecureRandom());
		msgSender.setSslProtocol("TLS");
		return msgSender;
	}

	protected WebServiceTemplate getWebServiceTemplate() {
		if (ws != null && isPerformed()) return this.ws;
		else return null;
	}

	protected WebServiceTemplate setUpSSLWebServiceTemplate() {
		log.info("Setting up https client with client keystore and truststore");
		if (ws != null && !isPerformed()) {
			try {
				ws.setMessageSender(setHttpsMessageSender());
				this.performed = true;
			} catch (UnrecoverableKeyException e) {
				log.error("Unrecoverable key exception..!!", e);
			} catch (KeyStoreException e) {
				log.error("Keystore exception..!!", e);
			} catch (NoSuchAlgorithmException e) {
				log.error("No such algorithm exception..!!", e);
			} catch (CertificateException e) {
				log.error("Certificate exception..!!", e);
			} catch (FileNotFoundException e) {
				log.error("File not found exception..!!", e);
			} catch (IOException e) {
				log.error("IO exception..!!", e);
			}
		}
		return ws;
	}

	private boolean isPerformed() {
		return performed;
	}

	protected TrustManagerFactory getTrustManagerFactory(File file,
			String trustpass) throws KeyStoreException,
			NoSuchAlgorithmException, CertificateException,
			FileNotFoundException, IOException {

		return getTrustManagerFactory(file, trustpass.toCharArray());
	}

	protected TrustManagerFactory getTrustManagerFactory(File file,
			char[] trustpass) throws KeyStoreException, IOException,
			NoSuchAlgorithmException, CertificateException,
			FileNotFoundException {

		KeyStore trustStore = KeyStore.getInstance("JKS");
		trustStore.load(new FileInputStream(file), trustpass);

		TrustManagerFactory trustManagerFactory = TrustManagerFactory
				.getInstance(trustAlgorithm);
		trustManagerFactory.init(trustStore);
		return trustManagerFactory;
	}

	protected KeyManagerFactory getKeyManagerFactory(File file,
			String keystorepass) throws UnrecoverableKeyException,
			KeyStoreException, NoSuchAlgorithmException, CertificateException,
			FileNotFoundException, IOException {

		return getKeyManagerFactory(file, keystorepass.toCharArray());
	}

	protected KeyManagerFactory getKeyManagerFactory(File file,
			char[] keystorepass) throws KeyStoreException, IOException,
			NoSuchAlgorithmException, CertificateException,
			FileNotFoundException, UnrecoverableKeyException {

		KeyStore keyStore = KeyStore.getInstance("JKS");
		keyStore.load(new FileInputStream(file), keystorepass);

		KeyManagerFactory keyManagerFactory = KeyManagerFactory
				.getInstance(keyManagerAlgorithm);
		keyManagerFactory.init(keyStore, keystorepass);
		return keyManagerFactory;
	}

}
